﻿#if ENABLE_WECHAT

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WeChatWASM;
using UnityEngine;
using UnityEngine.Networking;
using System.IO;

namespace Core
{
    public class WechatAssetHelper : Helper, IAssetHelper
    {
        private WXFileSystemManager fileManager;
        private const string ACCESS_OK = "access:ok";
        private const string STRING_ENCODING = "utf8";
        private const string BINARY_ENCODING = "binary";

        public override void OnInit()
        {
            fileManager = WeChatWASM.WX.GetFileSystemManager();
        }

        #region 文本

        public string LoadString(string path)
        {
            try
            {
                return fileManager.ReadFileSync(path, STRING_ENCODING);
            }
            catch (Exception e)
            {
                Debug.LogError(e.ToString());
                return null;
            }
        }

        public async ETTask<string> LoadStringAsync(string path, int timeout = 0)
        {
            var request = UnityWebRequest.Get(path);
            if (timeout != 0)
                request.timeout = timeout;

            await request.SendWebRequest();

            string content = "";

            if (request.result == UnityWebRequest.Result.Success)
            {
                content = request.downloadHandler.text;
            }
            else
            {
                Debug.LogError(request.error);
            }

            request.Dispose();
            return content;
        }

        public void SaveString(string path, string content)
        {
            SaveBytes(path, Encoding.UTF8.GetBytes(content));
        }

        public async ETTask SaveStringAsync(string path, string content)
        {
            await SaveBytesAsync(path, Encoding.UTF8.GetBytes(content));
        }

        #endregion

        #region 二进制

        public byte[] LoadBytes(string path)
        {
            try
            {
                return fileManager.ReadFileSync(path);
            }
            catch (Exception e)
            {
                Debug.LogError(e.ToString());
                return null;
            }
        }

        public async ETTask<byte[]> LoadBytesAsync(string path, int timeout = 0)
        {
            var request = UnityWebRequest.Get(path);
            if (timeout != 0)
                request.timeout = timeout;

            await request.SendWebRequest();

            byte[] content = null;

            if (request.result == UnityWebRequest.Result.Success)
            {
                content = request.downloadHandler.data;
            }
            else
            {
                Debug.LogError(request.error);
            }

            request.Dispose();
            return content;
        }

        public void SaveBytes(string path, byte[] bytes)
        {
            var folderPath = GetDirectoryName(path);
            if (!IsDirectoryExists(folderPath))
                fileManager.MkdirSync(folderPath, true);

            fileManager.WriteFileSync(path, bytes, BINARY_ENCODING);
        }

        public async ETTask SaveBytesAsync(string path, byte[] bytes)
        {
            var folderPath = GetDirectoryName(path);
            if (!IsDirectoryExists(folderPath))
                fileManager.MkdirSync(folderPath, true);

            var task = ETTask.Create();
            var option = new WriteFileParam();
            option.filePath = path;
            option.data = bytes;
            option.success = (result) =>
            {
                task.SetResult();
            };
            option.fail = (result) =>
            {
                task.SetException(new Exception($"save string async error. path:{path}, code:{result.errCode}, msg:{result.errMsg}"));
            };

            fileManager.WriteFile(option);

            await task;
        }

        #endregion

        public void DeleteDirectory(string path)
        {
            try
            {
                if (IsDirectoryExists(path))
                    fileManager.RmdirSync(path, true);
            }
            catch (Exception ex)
            {
                Log.Error(ex);
            }
        }

        public string GetDirectoryName(string path)
        {
            var lastIndex = path.LastIndexOf('/');
            return path.Substring(0, lastIndex);
        }

        public void DeleteFile(string path)
        {
            try
            {
                if (IsFileExists(path))
                    fileManager.UnlinkSync(path);
            }
            catch (Exception ex)
            {
                Log.Error(ex);
            }
        }

        public bool IsDirectoryExists(string path)
        {
            return fileManager.AccessSync(path) == ACCESS_OK;
        }

        public bool IsFileExists(string path)
        {
            return fileManager.AccessSync(path) == ACCESS_OK;
        }

        public AssetBundle LoadAssetBundle(string path)
        {
            var bytes = LoadBytes(path);
            return AssetBundle.LoadFromMemory(bytes);
        }

        public async ETTask<AssetBundle> LoadAssetBundleAsync(string path)
        {
            // 更节省内存的WXAssetBundle
            UnityWebRequest bundleReq = WXAssetBundle.GetAssetBundle(path);
            await bundleReq.SendWebRequest();
            if (bundleReq.result == UnityWebRequest.Result.Success)
            {
                // DownloadHandlerAssetBundle => DownloadHandlerWXAssetBundle
                AssetBundle bundle = (bundleReq.downloadHandler as DownloadHandlerWXAssetBundle).assetBundle; 
                return bundle;
            }
            else
            {
                Debug.LogError($"资源包加载失败, path:{path}, error:{bundleReq.error}");
                return null;
            }
        }

        public void UnloadAssetBundle(AssetBundle assetBundle)
        {
            if (WXAssetBundle.bundle2path.ContainsKey(assetBundle))
            {
                //bundle还是AssetBundle类型，但需要调用扩展方法WXUnload()才可真正卸载
                assetBundle.WXUnload(true);
            }
            else
            {
                assetBundle.Unload(true);
            }
        }
    }
}

#endif